package com.cmc6.dict.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmc6.common.exception.BaseBizCodeEnum;
import com.cmc6.common.mapper.DictMapper;
import com.cmc6.common.model.dto.AddOrderNoDTO;
import com.cmc6.common.model.dto.NotEmptyIdSet;
import com.cmc6.common.model.dto.NotNullId;
import com.cmc6.common.model.entity.BaseEntityThree;
import com.cmc6.common.model.entity.BaseEntityTwo;
import com.cmc6.common.model.entity.DictDO;
import com.cmc6.common.model.enums.DictTypeEnum;
import com.cmc6.common.util.ApiResult;
import com.cmc6.common.util.MyEntityUtil;
import com.cmc6.dict.exception.BizCodeEnum;
import com.cmc6.dict.model.dto.DictInsertOrUpdateDTO;
import com.cmc6.dict.model.dto.DictPageDTO;
import com.cmc6.dict.model.vo.DictTreeVO;
import com.cmc6.dict.service.DictService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, DictDO> implements DictService {

    /**
     * 新增/修改 字典
     */
    @Override
    @Transactional
    public String insertOrUpdate(DictInsertOrUpdateDTO dto) {

        // 类型：1 字典 2 字典项
        if (1 == dto.getType()) {
            // 字典 key和 name不能重复
            Long count = lambdaQuery().eq(DictDO::getType, 1)
                .and(i -> i.eq(DictDO::getDictKey, dto.getDictKey()).or().eq(DictDO::getName, dto.getName()))
                .eq(BaseEntityThree::getEnableFlag, 1).ne(dto.getId() != null, BaseEntityTwo::getId, dto.getId())
                .count();
            if (count != 0) {
                ApiResult.error(BizCodeEnum.SAME_KEY_EXISTS);
            }

            dto.setValue((byte)-1); // 字典的value为 -1
        } else if (2 == dto.getType()) {

            if (dto.getValue() == null) {
                ApiResult.error(BizCodeEnum.VALUE_CANNOT_BE_EMPTY);
            }

            // 字典项 value和 name不能重复
            Long count = lambdaQuery().eq(DictDO::getType, 2).eq(BaseEntityThree::getEnableFlag, 1)
                .eq(DictDO::getDictKey, dto.getDictKey())
                .and(i -> i.eq(DictDO::getValue, dto.getValue()).or().eq(DictDO::getName, dto.getName()))
                .ne(dto.getId() != null, BaseEntityTwo::getId, dto.getId()).count();
            if (count != 0) {
                ApiResult.error(BizCodeEnum.SAME_VALUE_EXISTS);
            }
        } else {
            ApiResult.error("操作失败：type【" + dto.getType() + "】不合法");
        }

        if (dto.getId() != null && dto.getType() == 1) {
            // 如果是修改，并且是字典，那么也需要修改 该字典的字典项的 dictKey
            DictDO one = lambdaQuery().eq(BaseEntityTwo::getId, dto.getId()).select(DictDO::getDictKey).one();
            if (one == null) {
                ApiResult.error("操作失败：字典不存在，请刷新重试");
            }
            if (!one.getDictKey().equals(dto.getDictKey())) {
                lambdaUpdate().eq(DictDO::getDictKey, one.getDictKey()).eq(DictDO::getType, 2)
                    .set(DictDO::getDictKey, dto.getDictKey()).update();
            }
        }

        DictDO dictDO = new DictDO();
        dictDO.setDictKey(dto.getDictKey());
        dictDO.setName(dto.getName());
        dictDO.setType(DictTypeEnum.getByCode(dto.getType()));
        dictDO.setValue(dto.getValue());
        dictDO.setOrderNo(dto.getOrderNo());
        dictDO.setEnableFlag(dto.isEnableFlag());
        dictDO.setRemark(MyEntityUtil.getNotNullStr(dto.getRemark()));
        dictDO.setId(dto.getId());
        saveOrUpdate(dictDO);

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 分页排序查询：字典
     */
    @Override
    public Page<DictDO> myPage(DictPageDTO dto) {
        return myPageRes(dto);
    }

    /**
     * 分页排序查询：字典-返回值
     */
    private Page<DictDO> myPageRes(DictPageDTO dto) {

        return lambdaQuery().like(StrUtil.isNotBlank(dto.getName()), DictDO::getName, dto.getName())
            .like(StrUtil.isNotBlank(dto.getRemark()), BaseEntityThree::getRemark, dto.getRemark())
            .like(StrUtil.isNotBlank(dto.getDictKey()), DictDO::getDictKey, dto.getDictKey())
            .eq(dto.getId() != null, BaseEntityTwo::getId, dto.getId())
            .eq(dto.getType() != null, DictDO::getType, dto.getType())
            .eq(dto.getEnableFlag() != null, BaseEntityThree::getEnableFlag, dto.getEnableFlag()).page(dto.getPage());

    }

    /**
     * 查询字典（树结构）
     */
    @Override
    public List<DictTreeVO> tree(DictPageDTO dto) {

        dto.setPageSize(-1); // 不分页
        Page<DictDO> selectPage = myPageRes(dto);
        List<DictDO> records = selectPage.getRecords();

        List<DictTreeVO> resList = new ArrayList<>(); // 本接口返回值

        if (records.size() == 0) {
            return resList;
        }

        // 过滤出为字典项的数据，目的：查询其所属字典，封装成树结构
        List<DictDO> dictItemList = new ArrayList<>();
        for (DictDO item : records) {
            // 防止乱序
            if (2 == item.getType().getCode()) {
                dictItemList.add(item);
            }
        }

        if (dictItemList.size() == 0) {
            // 如果没有字典项类型数据，则直接返回
            for (DictDO item : records) {
                DictTreeVO treeVO = BeanUtil.copyProperties(item, DictTreeVO.class);
                resList.add(treeVO);
            }
            return resList;
        }

        // 否则查询出字典项所属字典的信息
        List<DictDO> allDictList =
            records.stream().filter(item -> 1 == item.getType().getCode()).collect(Collectors.toList());

        Set<Long> dictIdSet = allDictList.stream().map(BaseEntityTwo::getId).collect(Collectors.toSet());
        Set<String> dictKeySet = dictItemList.stream().map(DictDO::getDictKey).collect(Collectors.toSet());

        // 查询数据库
        List<DictDO> dbDictList = lambdaQuery().notIn(dictIdSet.size() != 0, BaseEntityTwo::getId, dictIdSet)
            .in(dictKeySet.size() != 0, DictDO::getDictKey, dictKeySet).eq(DictDO::getType, 1).list();

        // 拼接本次返回值所需的所有字典
        allDictList.addAll(dbDictList);

        for (DictDO item : allDictList) {
            DictTreeVO treeVO = BeanUtil.copyProperties(item, DictTreeVO.class);
            resList.add(treeVO);
        }

        // 封装 children
        for (DictDO item : dictItemList) {
            DictTreeVO treeVO = BeanUtil.copyProperties(item, DictTreeVO.class);
            for (DictTreeVO subItem : resList) {
                if (subItem.getDictKey().equals(item.getDictKey())) {
                    List<DictTreeVO> children = subItem.getChildren();
                    if (children == null) {
                        children = new ArrayList<>();
                        subItem.setChildren(children); // 重新指定对象地址引用
                    }
                    children.add(treeVO);
                    break;
                }
            }
        }

        return resList;
    }

    /**
     * 删除字典
     */
    @Override
    @Transactional
    public String deleteByIdSet(NotEmptyIdSet notEmptyIdSet) {

        Set<Long> idSet = notEmptyIdSet.getIdSet();

        // 根据 idSet，查询出数据库对应的值
        List<DictDO> dbList = listByIds(notEmptyIdSet.getIdSet());

        if (CollUtil.isEmpty(dbList)) {
            return BaseBizCodeEnum.API_RESULT_OK.getMsg();
        }

        // 直接先根据 idSet删除
        removeByIds(idSet);

        // 筛选出 type = 1（字典）的数据
        List<DictDO> dictParentList =
            dbList.stream().filter(item -> 1 == item.getType().getCode()).collect(Collectors.toList());

        if (CollUtil.isEmpty(dictParentList)) {
            // 如果全是子级，则直接返回操作成功
            return BaseBizCodeEnum.API_RESULT_OK.getMsg();
        }

        // 如果删除是字典项的父级，则把其下的字典项也跟着删除了
        Set<String> keySet = dictParentList.stream().map(DictDO::getDictKey).collect(Collectors.toSet());
        lambdaUpdate().in(DictDO::getDictKey, keySet).remove();

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 通过主键id，查看详情
     */
    @Override
    public DictDO infoById(NotNullId notNullId) {

        return getById(notNullId.getId());
    }

    /**
     * 通过主键 idSet，加减排序号
     */
    @Override
    @Transactional
    public String addOrderNo(AddOrderNoDTO dto) {
        if (dto.getNumber() == 0) {
            return BaseBizCodeEnum.API_RESULT_OK.getMsg();
        }

        List<DictDO> listByIds = listByIds(dto.getIdSet());

        for (DictDO item : listByIds) {
            item.setOrderNo(item.getOrderNo() + dto.getNumber());
        }

        updateBatchById(listByIds);

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }
}




